#ifndef SCANNER_H
#define SCANNER_H
#include <string>
#include <vector>
#include "token.h"
#include "scanner-helper.h"

namespace tinyscript{
namespace internal{
// The scanner is used to scan the text and returns the token.
// This scanner will be simple and tight since the required text
// state is very small. Anyway , the scanner is used as the first
// step to walk through the source code.

class Scanner {
public:
	enum {
		MODE_IGNORE_WHITESPACE,
		MODE_NORMAL
	};
    // Step the scanner to fetch the next possible token . This is the most useful
    Token Advance( int m = MODE_NORMAL );
    // The peek function is used to peek ahead of the token , it will not change the
    // scanner, but gives you hint of the next token inside of the stream.
    Token Peek( int m = MODE_NORMAL );
	// N step forward peeking routine.
	Token Peek( const Token& where , int m = MODE_NORMAL );

	void PutBack( const Token& t ) {
		assert(t.index_end() == current_index_);
		current_index_ = t.index_start();
		c0_ = buffer_.CharAt(t.index_start());
		// check the line number
		if( t.token() == Token::TT_WHITESPACE ) {
			char_t c = buffer_.CharAt(t.index_start());
			if( c == '\n' )
				--current_line_;
		}
	}

    Scanner( const std::vector<char_t>& buf ) :
        buffer_(buf),
        current_index_(0),
		current_line_(0){}

	const std::vector<char_t>& buffer() const {
		return buffer_.buffer();
	}

	size_t current_index() const {
		return current_index_;
	}

	// Current Line Number
	size_t current_line() const {
		return current_line_;
	}

	const std::string& error_description() const {
		return error_description_;
	}

private:
	// Report the lexer error. This is used 
	// only once the scanner returns an error
	void ReportError( const std::string& error , char_t cha = 0 );

private:
    Token Step( size_t* pos , char_t c0 , size_t index , int m );
    // The simple scan process, this process will scan the operator
    bool ScanOperators( Token* t , size_t* pos , char_t c0 , size_t index );
    bool ScanSymbolOrKeyword( Token* t , size_t* pos , char_t c0 , size_t index );
    void ScanWhitespace( Token* t , size_t* pos , char_t c0 , size_t index );
    void PeekChar( char_t* nc , size_t* ni ) const {
        *nc = buffer_.CharAt(current_index_);
        *ni = current_index_+1;
    }
	void PeekChar( size_t where , char* nc ) {
		*nc = buffer_.CharAt(where);
	}
    void AdvanceChar() {
        c0_ = buffer_.CharAt(current_index_);
        ++current_index_;
    }

private:

    bool GetSymbol( Token* t , size_t* pos , char_t c0 , size_t index );
    bool GetString(Token*t , size_t* pos, char_t c0 , size_t index );
    bool GetNumber(Token*t , size_t* pos , char_t c0 , size_t index );
private:
    internal::StringBufferHelper buffer_;
    char_t c0_; // the current scanned characters
    size_t current_index_ ; // the current index of the scanner inside of the stream
	size_t current_line_;
	std::string error_description_;


	DISALLOW_COPY_AND_ASSIGN(Scanner);
};

}
}

#endif // SCANNER_H
